#include "iipch.h"
#include "mmConnect_PLC.h"

#define iiCONNECT_PLC_LENGTH_UINT 1
#define iiCONNECT_PLC_LENGTH_int 2
#define iiCONNECT_PLC_LENGTH_float 4
#define iiCONNECT_PLC_MAXLENGTH_CString 100

#define iiCONNECT_PLC_RACK		0
#define iiCONNECT_PLC_SLOT		1
#define iiCONNECT_PLC_PLC_PORT	102

#include "xxFileProcess.h"
#include "mmFile_Paras.h"

_mmConnect_PLC mmConnect_PLC;


bool _mmConnect_PLC::_Init() {
	if (iiProject.Flag_InitSystem == false) {
		return false;
	}

	IPAddress = xx::ReadAndUpdateini(iniField, L"IPaddress", L"", mmFile_Paras.iniModelPath());
	Flag_AutoConnect = xx::ReadAndUpdateini(iniField, L"AutoConnect", 1, mmFile_Paras.iniModelPath());


	

	W_Test.Init(2000, 0, ooPlcFormat_UINT);
	R_Test.Init(2001, 0, ooPlcFormat_UINT);

	AfxBeginThread(ThreadAutoConnect, this);
	AfxBeginThread(ThreadWatchdog, this);

	Flag_Inited = TRUE;
	return TRUE;
}

_mmConnect_PLC::~_mmConnect_PLC() {
	_Uninit();
}

bool _mmConnect_PLC::_Uninit() {
	if (Flag_Inited == false) {
		return TRUE;
	}
	Disconnect();
	return TRUE;
}


bool _mmConnect_PLC::Connect(CString varIPAddress, bool ForceConnect) {
	if (Flag_Connected == TRUE && ForceConnect == false) {
		return TRUE;
	}
	mmConnect_PLC.Disconnect();
	Sleep(100);

	if (varIPAddress == L"NULL" || varIPAddress == L"") {
		varIPAddress = IPAddress;
	}
	else {
		IPAddress = varIPAddress;
	}

	USES_CONVERSION;
	fds.rfd = openSocket(iiCONNECT_PLC_PLC_PORT, T2A(IPAddress));
	fds.wfd = fds.rfd;

	if (fds.rfd > 0) {
		di = daveNewInterface(fds, (char*)"myPLC", daveProtoMPI, daveProtoISOTCP, daveSpeed187k);
		if (daveInitAdapter(di) == 0) {
			dc = daveNewConnection(di, 2, iiCONNECT_PLC_RACK, iiCONNECT_PLC_SLOT);
			if (daveConnectPLC(dc) == 0) {
				if (plc_mutex != NULL) {
					delete plc_mutex;
				}
				plc_mutex = CreateMutex(NULL, false, L"plc_mutex");
				Flag_Connected = TRUE;
				return TRUE;
			}
		}
	}
	Flag_Connected = false;
	return false;
}

void _mmConnect_PLC::Disconnect()
{
	if (dc != NULL) {
		daveDisconnectPLC(dc);
		daveFree(dc);
		dc = NULL;
	}
	if (di != NULL) {
		daveDisconnectAdapter(di);
		daveFree(dc);
		di = NULL;
	}
	if (fds.rfd != NULL) {
		closeSocket(fds.rfd);
		fds.rfd = NULL;
	}
	Flag_Connected = false;
}

bool _mmConnect_PLC::Read(int varDB, int varStartPos, int varLength, BYTE* data) {
	if (Flag_Connected == false) {
		return false;
	}
	WaitForSingleObject(plc_mutex, INFINITE);
	try {
		if (daveReadBytes(dc, daveDB, varDB, varStartPos, varLength, data) == 0) {
			ReleaseMutex(plc_mutex);
			return TRUE;
		}
	}
	catch (...) {
	}

	ReleaseMutex(plc_mutex);
	Disconnect();
	Flag_Connected = false;
	return false;
}

bool _mmConnect_PLC::Write(int varDB, int varStartPos, int varLength, BYTE* data) {
	if (Flag_Connected == false) {
		return false;
	}

	WaitForSingleObject(plc_mutex, INFINITE);
	try {
		if (daveWriteBytes(dc, daveDB, varDB, varStartPos, varLength, data) == 0) {
			ReleaseMutex(plc_mutex);
			return TRUE;
		}
	}
	catch (...) {
	}
	ReleaseMutex(plc_mutex);
	Disconnect();
	Flag_Connected = false;
	return false;
}

UINT _mmConnect_PLC::Read_UINT(int varDB, int varStartPos) {
	BYTE x;
	Read(varDB, varStartPos, iiCONNECT_PLC_LENGTH_UINT, &x);
	return (UINT)x;
}

int _mmConnect_PLC::Read_int(int varDB, int varStartPos) {
	short itx;
	BYTE x[iiCONNECT_PLC_LENGTH_int], y[iiCONNECT_PLC_LENGTH_int];
	Read(varDB, varStartPos, iiCONNECT_PLC_LENGTH_int, x);
	for (int i = 0; i < iiCONNECT_PLC_LENGTH_int; i++) {
		y[i] = x[iiCONNECT_PLC_LENGTH_int - i - 1];
	}
	ByteToInt(&itx, y);
	return (int)itx;
}

float _mmConnect_PLC::Read_float(int varDB, int varStartPos) {
	float flt;
	BYTE x[iiCONNECT_PLC_LENGTH_float], y[iiCONNECT_PLC_LENGTH_float];
	Read(varDB, varStartPos, iiCONNECT_PLC_LENGTH_float, x);
	for (int i = 0; i < iiCONNECT_PLC_LENGTH_float; i++) {
		y[i] = x[iiCONNECT_PLC_LENGTH_float - i - 1];
	}
	ByteToFloat(&flt, y);
	return flt;
}

CString _mmConnect_PLC::Read_CString(int varDB, int varStartPos, int varLength) {
	if (varLength == 0) {
		return L"";
	}

	CString cstr;
	char str[iiCONNECT_PLC_MAXLENGTH_CString] = { 0 };
	if (varLength == -2){
		varLength = Read_int(varDB, varStartPos);
		Read(varDB, varStartPos + 2, varLength, (BYTE*)str);
	}
	else {
		Read(varDB, varStartPos, varLength, (BYTE*)str);
	}
	USES_CONVERSION;
	cstr.Format(L"%s", A2T(str));
	return cstr;
}

bool _mmConnect_PLC::Write_UINT(UINT x, int varDB, int varStartPos) {
	BYTE y = BYTE(x);
	return Write(varDB, varStartPos, iiCONNECT_PLC_LENGTH_UINT, &y);
}

bool _mmConnect_PLC::Write_int(int itx, int varDB, int varStartPos) {
	BYTE x[iiCONNECT_PLC_LENGTH_int], y[iiCONNECT_PLC_LENGTH_int];
	CString cstr;
	cstr.Format(L"%d", itx);
	int x_Temp = _ttoi(cstr);
	short sx = (short)(x_Temp);
	IntToBYTE(&sx, x);
	for (int i = 0; i < iiCONNECT_PLC_LENGTH_int; i++) {
		y[i] = x[iiCONNECT_PLC_LENGTH_int - i - 1];
	}
	return Write(varDB, varStartPos, iiCONNECT_PLC_LENGTH_int, y);
}

bool _mmConnect_PLC::Write_float(float flt, int varDB, int varStartPos) {
	BYTE x[iiCONNECT_PLC_LENGTH_float], y[iiCONNECT_PLC_LENGTH_float];
	FloatToBYTE(&flt, x);
	for (int i = 0; i < iiCONNECT_PLC_LENGTH_float; i++) {
		y[i] = x[iiCONNECT_PLC_LENGTH_float - i - 1];
	}
	return Write(varDB, varStartPos, iiCONNECT_PLC_LENGTH_float, y);

}

bool _mmConnect_PLC::Write_CString(CString cstr, int varDB, int varStartPos, int varLength) {
	if (varLength == 0) {
		return false;
	}

	USES_CONVERSION;
	char * str = T2A(cstr);
	if (varLength == -2) {
		varLength = cstr.GetLength();
		if (Write_int(varLength, varDB, varStartPos) == false) {
			return false;
		}
		return Write(varDB, varStartPos + 2, varLength, (BYTE*)str);
	}
	
	return Write(varDB, varStartPos, varLength, (BYTE*)str);
}


int _mmConnect_PLC::GetDefaultLength(ooPlcFormat varPlcFormat) {
	if (varPlcFormat == ooPlcFormat_UINT) {
		return iiCONNECT_PLC_LENGTH_UINT;
	}
	else if (varPlcFormat == ooPlcFormat_int) {
		return iiCONNECT_PLC_LENGTH_int;
	}
	else if (varPlcFormat == ooPlcFormat_float) {
		return iiCONNECT_PLC_LENGTH_float;
	}
	
	return 0;
}


void uuPlcItem::Init(int varDB, int varStartPos, ooPlcFormat varFormat, int varLength) {
	DB = varDB;
	StartPos = varStartPos;
	Format = varFormat;
	Length = (varFormat == ooPlcFormat_CString) ? varLength : mmConnect_PLC.GetDefaultLength(varFormat);
}

void uuPlcItem::ChangeFormat(ooPlcFormat varPlcFormat) {
	Format = varPlcFormat;
	Length = mmConnect_PLC.GetDefaultLength(varPlcFormat);
}

void _mmConnect_PLC::ByteToFloat(float *floatNum, BYTE* byteArry) {
	char* pchar = (char*)floatNum;

	for (int i = 0; i < sizeof(float); i++) {
		*pchar = *byteArry;
		pchar++;
		byteArry++;
	}
}

void _mmConnect_PLC::ByteToInt(short *intNum, BYTE* byteArry) {

	char* pchar = (char*)intNum;

	for (int i = 0; i < sizeof(short); i++) {
		*pchar = *byteArry;
		pchar++;
		byteArry++;
	}
}

void _mmConnect_PLC::FloatToBYTE(float *floatNum, BYTE* byteArry) {
	char* pchar = (char*)floatNum;

	for (int i = 0; i < sizeof(float); i++) {
		*byteArry = *pchar;
		pchar++;
		byteArry++;
	}
}

void _mmConnect_PLC::IntToBYTE(short*intNum, BYTE* byteArry) {
	char* pchar = (char*)intNum;

	for (int i = 0; i < sizeof(short); i++) {
		*byteArry = *pchar;
		pchar++;
		byteArry++;
	}
}

UINT _mmConnect_PLC::ThreadAutoConnect(LPVOID pParam) {
	while (iiProject.Flag_ExitSystem == false) {
		Sleep(1000);
		if (mmConnect_PLC.Flag_Connected == TRUE) {
			continue;
		}
		if (mmConnect_PLC.Flag_AutoConnect == false) {
			continue;
		}
		mmConnect_PLC.Connect(mmConnect_PLC.IPAddress, false);
	}
	return 0;
}


UINT _mmConnect_PLC::ThreadWatchdog(LPVOID pParam) {
	while (iiProject.Flag_ExitSystem == false) {
		Sleep(1000);
		if (mmConnect_PLC.Flag_Connected == false) {
			continue;
		}
		if (mmConnect_PLC.Flag_AutoWatchDog == false) {
			continue;
		}
		switch (mmConnect_PLC.W_Watchdog.Format) {
		case ooPlcFormat_int:
			mmConnect_PLC.W_Watchdog.Write_int(mmConnect_PLC.W_Watchdog_Value++);
			break;
		case ooPlcFormat_UINT:
			if (mmConnect_PLC.W_Watchdog_Value >= 255) {
				mmConnect_PLC.W_Watchdog_Value = 0;
			}
			mmConnect_PLC.W_Watchdog.Write_UINT(mmConnect_PLC.W_Watchdog_Value++);
			break;
		default:
			break;
		}

		switch (mmConnect_PLC.R_Watchdog.Format) {
		case ooPlcFormat_int:
			mmConnect_PLC.R_Watchdog_Value = mmConnect_PLC.R_Watchdog.Read_int();
			break;
		case ooPlcFormat_UINT:
			mmConnect_PLC.R_Watchdog_Value = mmConnect_PLC.R_Watchdog.Read_UINT();
			break;
		default:
			break;
		}
		
		
	}
	return 0;
}

UINT uuPlcItem::Read_UINT() {
	if (Format != ooPlcFormat_UINT) {
		return 0;
	}
	return mmConnect_PLC.Read_UINT(DB, StartPos);
}

int uuPlcItem::Read_int() {
	if (Format != ooPlcFormat_int) {
		return 0;
	}
	return mmConnect_PLC.Read_int(DB, StartPos);
}

float uuPlcItem::Read_float() {
	if (Format != ooPlcFormat_float) {
		return 0;
	}
	return mmConnect_PLC.Read_float(DB, StartPos);
}

CString uuPlcItem::Read_CString() {
	if (Format != ooPlcFormat_CString || Length == 0) {
		return L"";
	}
	return mmConnect_PLC.Read_CString(DB, StartPos, Length);
}


bool uuPlcItem::Write_UINT(UINT x) {
	if (Format != ooPlcFormat_UINT) {
		return false;
	}
	return mmConnect_PLC.Write_UINT(x, DB, StartPos);
}

bool uuPlcItem::Write_int(int itx) {
	if (Format != ooPlcFormat_int) {
		return false;
	}
	return mmConnect_PLC.Write_int(itx, DB, StartPos);
}

bool uuPlcItem::Write_float(float flt) {
	if (Format != ooPlcFormat_float) {
		return false;
	}
	return mmConnect_PLC.Write_float(flt, DB, StartPos);
}

bool uuPlcItem::Write_CString(CString cstr) {
	if (Format != ooPlcFormat_CString || Length == 0) {
		return false;
	}
	return mmConnect_PLC.Write_CString(cstr, DB, StartPos, Length);
}


